#include "ogreapplication.h"

#include <CEGUI/CEGUISchemeManager.h>

using namespace Ogre;
using namespace std;

namespace
{
    void
    parseResourceLocationFrom(const String& resourcesFileName)
    {
        // Load resource paths from config file
        ConfigFile cf;
        cf.load(resourcesFileName);
        // Go through all sections & settings in the file
        ConfigFile::SectionIterator seci = cf.getSectionIterator();
        while (seci.hasMoreElements())
        {
            String secName = seci.peekNextKey();
            ConfigFile::SettingsMultiMap* settings = seci.getNext();
            for (ConfigFile::SettingsMultiMap::iterator i = settings->begin();
                    i != settings->end(); ++i)
            {
                String typeName = i->first;
                String archName = i->second;
                ResourceGroupManager::getSingleton().addResourceLocation(
                    archName, typeName, secName);
            }
        }
    }
}
//************************************************************
// Implementation of OgreApplication
//************************************************************
OgreApplication::OgreApplication(Ogre::String name)
        : mName(name)
        , mRoot(NULL)
        , mWindow(NULL)
        , mEventProcessor(NULL)
        , mGUIRenderer(NULL)
        , mGUISystem(NULL)
        , mEditorGuiSheet(NULL)
        , move(Vector3(0,0,0))
        , mQuitRequested(false)

{}
OgreApplication::~OgreApplication()
{
    if (mEventProcessor) delete mEventProcessor;
    if (mTrackball)      delete mTrackball;
    if (mGUISystem)      delete mGUISystem;
    if (mGUIRenderer)    delete mGUIRenderer;
    if (mRoot)           delete mRoot;
}
void
OgreApplication::addResourceLocationFrom(const String& fileName)
{
    mResourcesFileNames.push_back(fileName);
}
void
OgreApplication::create(const String& pluginsFileName,
                        const String& configFileName,
                        const String& logFileName,
                        SceneType sceneType)
{
    //////////////////////////////////////////////////////////////
    // Initialization of Root and RenderWindow
    //////////////////////////////////////////////////////////////
    mRoot = new Root(pluginsFileName,configFileName,logFileName);
    if (!mRoot->restoreConfig())
    {
        if (!mRoot->showConfigDialog())
        {
            throw Exception(0,"user quitted config dialog","OgreApplication::init()",__FILE__,__LINE__);
        }
    }
    mWindow = mRoot->initialise(true,mName);
    //////////////////////////////////////////////////////////////
    // Initializing resources
    //////////////////////////////////////////////////////////////
    for_each(mResourcesFileNames.begin(),mResourcesFileNames.end(),parseResourceLocationFrom);
    ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
    //////////////////////////////////////////////////////////////
    // Initialization of Scene
    //////////////////////////////////////////////////////////////
    mSceneManager = mRoot->createSceneManager(sceneType,"sceneManager");
    mCamera = mSceneManager->createCamera("Camera");
    mCamera->setPosition(Vector3(0.0f,0.0f,500.0f));
    mCamera->lookAt(Vector3(0.0f,0.0f,0.0f));
    mCamera->setNearClipDistance(5.0f);
    mCamera->setFarClipDistance(5000.0f);
    ////////////////////////////////////////////////////////////
    // Binding of Scene and RenderWindow
    ////////////////////////////////////////////////////////////
    mViewport = mWindow->addViewport(mCamera);
    mViewport->setBackgroundColour(ColourValue(0.0f,0.0f,0.0f));
    mCamera->setAspectRatio(Real(mViewport->getActualWidth()) /
                            Real(mViewport->getActualHeight()));
    ////////////////////////////////////////////////////////////
    // Initialize GUI
    ////////////////////////////////////////////////////////////
    mGUIRenderer = new CEGUI::OgreCEGUIRenderer(mWindow,Ogre::RENDER_QUEUE_OVERLAY,
                   false,3000,
                   mSceneManager);
    mGUISystem = new CEGUI::System(mGUIRenderer);

    CEGUI::SchemeManager::getSingleton().loadScheme((CEGUI::utf8*)"TaharezLookSkin.scheme");
    mGUISystem->setDefaultMouseCursor(reinterpret_cast<const CEGUI::utf8*>("TaharezLook"),
                                      reinterpret_cast<const CEGUI::utf8*>("MouseArrow"));
    CEGUI::MouseCursor::getSingleton().setImage(CEGUI::System::getSingleton().getDefaultMouseCursor());
    mGUISystem->setDefaultFont((CEGUI::utf8*)"BlueHighway-12");
    mEditorGuiSheet= CEGUI::WindowManager::getSingleton().loadWindowLayout((CEGUI::utf8*)"visage.layout");
    mGUISystem->setGUISheet(mEditorGuiSheet);
    ////////////////////////////////////////////////////////////
    // Managing input
    ////////////////////////////////////////////////////////////
    mRoot->addFrameListener(this);

    mTrackball = new Trackball(mGUIRenderer,mGUISystem,mCamera,mSceneManager);

    mEventProcessor = new EventProcessor();
    mEventProcessor->addKeyListener(this);
    mEventProcessor->addMouseListener(mTrackball);
    mEventProcessor->addMouseMotionListener(mTrackball);


 CEGUI::WindowManager& wmgr = CEGUI::WindowManager::getSingleton();
 wmgr.getWindow((CEGUI::utf8*)"VisageGui/Control/Quit")->subscribeEvent(CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&OgreApplication::handleQuit, this));
    //////////////////////////////////////////////////////////////
    //  User initialization (subclassed)
    //////////////////////////////////////////////////////////////
    init();
}
void
OgreApplication::run()
{
    mEventProcessor->initialise(mWindow);
    mEventProcessor->startProcessingEvents();
    mRoot->startRendering();
}
void
OgreApplication::keyClicked(KeyEvent *e)
{}
void
OgreApplication::keyPressed(KeyEvent *e)
{}
void
OgreApplication::keyReleased(KeyEvent *e)
{}
bool
OgreApplication::frameStarted(const FrameEvent& evt)
{
    return true;
}
bool
OgreApplication::frameEnded(const FrameEvent& evt)
{

    mCamera->moveRelative(move);

    return !mQuitRequested;
}
void
OgreApplication::init()
{}
void
OgreApplication::requestQuit()
{
    mQuitRequested = true;
}
bool OgreApplication::handleQuit(const CEGUI::EventArgs& e)
{
   mQuitRequested = true;
   return true;
}

